// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WorkTemplate.cs" company="AzureContrib (Open source library http://azurecontrib.codeplex.com)">
//   Microsoft Public License (Ms-PL)
// </copyright>
// <summary>
//   A template for running a piece of <see cref="IWorkItem" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics;

using AzureContrib.WindowsAzure.Diagnostics;
using AzureContrib.WindowsAzure.Properties;
using AzureContrib.WindowsAzure.ServiceRuntime.ServiceLocation;

namespace AzureContrib.WindowsAzure.WorkServices
{
	/// <summary>
	/// A template for running a piece of <see cref="IWorkItem"/>
	/// </summary>
	internal sealed class WorkTemplate : Lazy<IWork>, /*IWork,*/ IBuilderUser
	{
		private readonly Lazy<IWork> lazyWorkToDo;
		private readonly ITrace trace;

		private IBuilder builder;

		/// <summary>
		/// Initializes a new instance of the <see cref="WorkTemplate"/> class. 
		/// Create a template class that runs a <paramref name="lazyWorkToDo"/> and logs using the <paramref name="trace"/>.
		/// </summary>
		/// <param name="lazyWorkToDo">
		/// The work to do.
		/// </param>
		/// <param name="trace">
		/// The current <see cref="ITrace"/>
		/// </param>
		public WorkTemplate(Lazy<IWork> lazyWorkToDo, ITrace trace)
		{
			Assumes.NotNull(lazyWorkToDo, "workToDo");
			Assumes.NotNull(trace, "trace");

			this.lazyWorkToDo = lazyWorkToDo;
			this.trace = trace;
		}

		public new IWork Value
		{
			get
			{
				var value = lazyWorkToDo.Value;

				var theBuilder = builder;
				if (theBuilder != null)
				{
					var builderUser = value as IBuilderUser;
					if (builderUser != null)
					{
						builderUser.SetBuilder(theBuilder);
					}

					var lazyBuilderUser = value as ILazyBuilderUser;
					if (lazyBuilderUser != null)
					{
						lazyBuilderUser.SetBuilder(new Lazy<IBuilder>(() => theBuilder));
					}
				}

				return value;
			}
		}

		/// <summary>
		/// Call the actual work <see cref="IWorkItem.DoWork"/>.
		/// </summary>
		public void DoWork()
		{
			trace.Verbose(string.Format(Strings.WorkTemplateStarting, Value.Name));
			var stopwatch = new Stopwatch();

			try
			{
				stopwatch.Start();
				Value.DoWork();
			}
			catch (WorkException we)
			{
				trace.Error(Strings.WorkTemlpateExecutionException, Value.Name, we.Message);
			}
			finally
			{
				stopwatch.Stop();
				trace.Verbose(Strings.WorkTemlpateEnding, Value.Name, stopwatch.Elapsed);
			}
		}

		public void SetBuilder(IBuilder builder)
		{
			this.builder = builder;
		}
	}
}